package httpx

import (
	"context"
	"errors"
	"io"
	"log"
	"net/http"
	"sync"
)

type (
	ProcessFunc  = func(resp *http.Response) error
	ProgressFunc = func(cur, total, pct int64)
)

//New 创建一个请求对象
func New() *X {
	return &X{}
}

//Get Get
func Get(url string) *X {
	return New().Request(http.MethodGet, url, nil)
}

//Post Post
func Post(url string, body io.Reader) *X {
	return New().Request(http.MethodPost, url, body)
}

//X http 请求封装
type X struct {
	cli   *http.Client
	req   *http.Request
	pFn   ProcessFunc
	debug bool

	res *http.Response
	err error

	mu sync.Mutex
}

//Client 客户端对象
func (x *X) Client(cli *http.Client) *X {
	x.cli = cli
	return x
}

//SetRequest 请求对象
func (x *X) SetRequest(req *http.Request) *X {
	x.req = req
	return x
}

//Request 设置请求
func (x *X) Request(method string, url string, body io.Reader) *X {
	x.req, x.err = http.NewRequest(method, url, body)
	return x
}

//Debug 调试模式
func (x *X) Debug(yes ...bool) *X {
	x.debug = len(yes) == 0 || yes[0]
	return x
}

//Process 处理函数
func (x *X) Process(pFn ProcessFunc) *X {
	x.pFn = pFn
	return x
}

//Err 请求和处理过程的错误信息
func (x *X) Err() error {
	return x.err
}

//Exec 执行请求和处理
func (x *X) Exec(ctx context.Context) error {
	x.mu.Lock()
	defer x.mu.Unlock()

	if x.err != nil {
		return x.err
	}

	if x.req == nil {
		return errors.New("request is nil")
	}

	if ctx != nil {
		x.req = x.req.WithContext(ctx)
	}

	if x.cli == nil {
		x.cli = http.DefaultClient
	}

	if x.debug {
		log.Printf("request.url: %s", x.req.URL.String())
	}
	if x.res, x.err = x.cli.Do(x.req); x.err != nil {
		return x.err
	}

	if x.debug {
		log.Printf("response.status: %d: %s", x.res.StatusCode, x.res.Status)
		log.Printf("response.length: %s", humanSize(x.res.ContentLength))
	}

	if x.pFn != nil {
		x.err = x.pFn(x.res)
	}

	if x.debug && x.err != nil {
		log.Printf("response.err: %v", x.err)
	}

	return x.err
}

// Do 执行请求和处理
func (x *X) Do() error {
	return x.Exec(nil)
}
